<script setup lang="ts">
import { h, reactive, ref, computed } from "vue";
import { ElTabs, ElTabPane, ElTag, ElForm, vLoading, ElButton, ElMessage } from "element-plus"
import Nifi from "../../nifi";
import { get } from "lodash-es"
import { diff } from "../../util";
//
import PropertiesItemsElem from "../../components/properties-items/index.vue"
import PropertiesAddElem from "../../components/properties-items/add.vue";

import {t} from "../../i18n/index"

//
const emits = defineEmits<{ finish: [boolean],goTo:[any] }>();
const { nifi, id, disabled = false } = defineProps<{ nifi: Nifi, id: string, disabled?: boolean }>()
//
// 控制器服务的完整数据
const data = reactive<any>({})
let supportsSensitiveDynamicProperties = false;
// 表单数据
const model = reactive<Record<string, any>>({})
//
const descriptors = reactive<any>({})
const dynamicNames = reactive<string[]>([])
const dynamicDescriptors: Record<string, any> = {}
const loading = ref(true)
const isDisabled = computed(() => nifi.graph.mode.value == 'prod' || data.status?.runStatus == 'ENABLED' || disabled);
// 初始化 data
nifi.ControlService.detail(id).then(res => {
    Object.assign(data, res);
    //
    Object.assign(model, res.component.properties)
    //
    Object.assign(descriptors, res.component.descriptors)
    //
    supportsSensitiveDynamicProperties = res.component.supportsSensitiveDynamicProperties;
    loading.value = false;

})
//
const activeName = ref('props')
//
const LEVEL_TRANS: any = { DEBUG: t('cs-config-level-debug'), INFO: t('cs-config-level-info'), WARN: t('cs-config-level-warn'), ERROR: t('cs-config-level-error'), NONE: t('cs-config-level-none') }
const TAGTYPE_TRANS: any = { Processor: "primary", ControllerService: "success" }
//
const refreshDescriptor = async (name: string, sensitive = false) => {
    const url = `/nifi-api/controller-services/${id}/descriptors?propertyName=${name}&sensitive=${sensitive}`;
    //
    try {
        const res = await nifi.api.get(url);
        return res.propertyDescriptor;
    } catch (error) {
        ElMessage.error(t('cs-config-update-failed',{error}));
        console.error(error)
        return {};
    }
}
// 校验
const elFormRef = ref();
const validate = async () => {
    try {
        await elFormRef.value?.validate();
        return true;
    } catch (error) {
        ElMessage.warning(t('form-validate-failed'))
        return false;
    }
}
// 对比表单值和原始值的，获取对比之后的属性差集
const diffAttr = () => {
    const sd = data.component.properties
    // 提取变化值
    const d = diff(model, sd);
    // console.log('.........', model, sd)
    return d;
}
const addProperties = async (name: string, sensitive: boolean) => {
    return nifi.ControlService.addProperty(id, name, sensitive)
}
// 新增属性
const propsRef = ref();
const handleAdd = () => {
    activeName.value = 'props';
    //
    nifi.box.dialog((e) => h(PropertiesAddElem, {
        box: e, supportsSensitiveDynamicProperties, add: addProperties, onSubmit: (d) => {
            dynamicDescriptors[d.name] = d;
            dynamicNames.push(d.name);
            setTimeout(() => {
                propsRef.value?.$el.parentElement?.scrollTo({ top: propsRef.value.$el.offsetHeight + 200, behavior: "smooth" });
            }, 500)
        }
    },{showCancel:false}))
}
//
const errorMsg = reactive<{ verificationStepName: string, outcome: string, explanation: string }[]>([])
const checkLoading = ref(false)
const handleCheckAttr = async () => {
    checkLoading.value = true;
    //
    const d = diffAttr();
    try {
        let url = `/nifi-api/controller-services/${id}/config/analysis`;
        let res = await nifi.api.post(url, { configurationAnalysis: { componentId: id, properties: d || {} } });
        //
        url = `/nifi-api/controller-services/${id}/config/verification-requests`
        //
        res = await nifi.api.post(url, { request: { componentId: id, properties: d?.properties || {}, attributes: {} } })
        //
        url = `/nifi-api/controller-services/${id}/config/verification-requests/${res.request.requestId}`
        do {
            await new Promise((resolve) => setTimeout(() => resolve(true), 500));
            res = await nifi.api.get(url);
        }
        while (res.request.complete == false)
        res = await nifi.api.delete(url)
        //
        errorMsg.length = 0;
        errorMsg.push(...res.request.results);
    } catch (error) {
        ElMessage.error(t('cs-config-check-failed',{error}));
        console.error(error)
    }
    //
    checkLoading.value = false;
}
//
const handleCanel = () => {
    emits('finish', false)
}

const submitLoading = ref(false)
const handleSubmit = async () => {
    submitLoading.value = true;
    if (await validate()) {
        const properties = diffAttr();
        if (properties != undefined) {
            const d = { component: { id, properties }, disconnectedNodeAcknowledged: false, revision: data.revision };
            //
            await nifi.ControlService.update(d)
            emits('finish', true)
        } else {
            ElMessage.info(t('cs-config-notneed-update'))
            emits('finish', false)
        }

    }
    //
    submitLoading.value = false;
}

//
const handleGoTo = (d: any) => {
    // console.log('..........', d)
    emits('goTo',d);
    // const id = d.component.id;
    // const referenceType = d.component.referenceType;
    
    // 
    // if (referenceType == 'ControllerService') {
    //     const groupId = d.component.groupId;
    // }
    // else if (referenceType == 'Processor') {
    //     const groupId = d.component.parentGroupId;
    // }
}

</script>

<template>
    <div class="w-50vw h-50vh flex flex-col text-14px" v-loading="loading">
        <div class="h-40px flex items-center justify-between">
            <b>{{t('cs-config-text')}}</b>
            <div v-if="isDisabled">
                <el-button @click="handleCanel" type="primary" plain>{{t('box-cancel-text')}}</el-button>
            </div>
            <div v-else>
                <el-button type="success" plain :title="t('cs-config-add-prop')" @click="handleAdd">
                    <div class="i-typcn:plus-outline w-1em h-1em "></div>
                </el-button>
                <el-button type="warning" plain :title="t('cs-config-check-prop')" @click="handleCheckAttr" :loading="checkLoading">
                    <div class="i-ic:outline-fact-check w-1em h-1em"></div>
                </el-button>
                <el-button @click="handleCanel" type="default" plain>{{t('box-cancel-text')}}</el-button>
                <el-button @click="handleSubmit" type="primary" :loading="submitLoading">{{t('box-submit')}}</el-button>
            </div>
        </div>
        <!-- error message -->
        <div v-if="errorMsg.length > 0"
            class="max-h-200px overflow-auto w-full flex flex-col gap-8px scroll-thin text-12px lh-1.2em">
            <template v-for="msg in errorMsg">
                <div
                    :class="['p-x-8px p-y-4px b-1px b-solid rd-4px w-full box-border', msg.outcome == 'SUCCESSFUL' ? 'c-#67c23a b-#67c23a bg-#f0f9eb' : 'c-#f56c6c b-#f56c6c bg-#fef0f0']">
                    <div class="flex items-center gap-1em">
                        <i v-if="msg.outcome == 'SUCCESSFUL'" class="c-#67c23a i-mingcute:check-2-line w-1em h-1em"></i>
                        <i v-else class="c-#f56c6c i-icon-park-outline:error w-1em h-1em"></i>
                        <b>{{ msg.verificationStepName }}</b>
                    </div>

                    <div class="p-l-2em w-full">{{ msg.explanation }}</div>
                </div>
            </template>
        </div>
        <div class="flex-1 overflow-hidden p-y-8px box-border" v-if="data.component">
            <ElTabs v-model="activeName" class=" h-full w-full overflow-hidden">
                <ElTabPane ref="propsRef" name="props" :label="t('cs-config-props-label')" class="h-full p-x-8px box-border">
                    <ElForm ref="elFormRef" :model="model" label-width="200" label-position="left"
                        :disabled="isDisabled">
                        <template v-for="n in Object.keys(descriptors)" :key="n">
                            <PropertiesItemsElem v-model="model[n]" :prop="n" :descriptor="descriptors[n]"
                                :model="model" :nifi="nifi" :refresh="refreshDescriptor"></PropertiesItemsElem>
                        </template>
                        <!-- 动态新增的属性 -->
                        <template v-for="(k, i) in dynamicNames" :key="k">
                            <PropertiesItemsElem v-model="model[k]" :prop="k" :descriptor="dynamicDescriptors[k]"
                                :model="model" :autofocus="i + 1 == dynamicNames.length" :nifi="nifi"
                                :refresh="refreshDescriptor"></PropertiesItemsElem>
                        </template>
                    </ElForm>
                </ElTabPane>
                <ElTabPane name="detail" :label="t('cs-config-detail-label')" class="h-full p-x-8px box-border">
                    <div class="h-full w-full grid grid-cols-2 gap-x-24px">
                        <div class="h-full flex flex-col gap-8px">
                            <p class="flex"><i class="c-#999 font-not-italic min-w-100px">{{t('cs-config-detail-info-name')}}</i> <b
                                    class="c-#666 wb-all">{{
                                        data.component.name }}</b></p>
                            <p class="flex"><i class="c-#999 font-not-italic min-w-100px">{{t('cs-config-detail-info-id')}}</i> <b
                                    class="c-#666 wb-all">{{
                                        data.component.id
                                    }}</b></p>
                            <p class="flex"><i class="c-#999 font-not-italic min-w-100px">{{t('cs-config-detail-info-type')}}</i> <b
                                    class="c-#666 wb-all">{{
                                        data.component.type }}@{{
                                        data.component.bundle.version }}</b></p>
                            <p class="flex "><i class="c-#999 font-not-italic min-w-100px">{{t('cs-config-detail-info-group')}}</i> <b
                                    class="c-#666 wb-all">{{
                                        data.component.bundle.group }}@{{
                                        data.component.bundle.version }}</b></p>
                            <p class="flex"><i class="c-#999 font-not-italic min-w-100px">{{t('cs-config-detail-info-level')}}</i> <b
                                    class="c-#666 wb-all">{{
                                        get(LEVEL_TRANS, data.component.bulletinLevel) || data.component.bulletinLevel
                                    }}</b>
                            </p>

                            <fieldset class="flex-1 p-12px p-t-2px rd-4px b-gray-300 b-solid">
                                <legend class="c-#999">{{t('cs-config-detail-server-list')}}</legend>
                                <ul>
                                    <li v-for="api in data.component.controllerServiceApis" class="m-b-8px flex">
                                        <div class="i-tabler:point-filled w-1em h-1em lh-1.2em m-r-1em"></div>
                                        <div class="lh-1.2em">
                                            {{ api.type.split('.').pop() }}@{{ api.bundle.version }} from {{
                                                api.bundle.group
                                            }}-{{
                                                api.bundle.artifact }}
                                        </div>

                                    </li>
                                </ul>
                            </fieldset>

                        </div>
                        <div class="h-full flex flex-col">
                            <fieldset class="flex-1 overflow-auto scrollbar-thin p-12px p-t-2px rd-4px b-gray-300 b-solid">
                                <legend class="c-#999">{{t('cs-config-reference-compents-list')}}</legend>
                                <div class="flex flex-wrap gap-1em box-border">
                                    <ElTag v-for="d in data.component.referencingComponents"
                                        :class="'cursor-pointer p-10px'" @click="() => handleGoTo(d)" :title="t('cs-config-reference-compents-title')"
                                        :type="get(TAGTYPE_TRANS, d.component.referenceType) || 'info'">
                                        {{ d.component.name }}
                                    </ElTag>
                                </div>

                            </fieldset>
                        </div>
                    </div>
                </ElTabPane>
                <ElTabPane class="h-full p-x-8px box-border" name="desc" :label="t('cs-config-desc-label')">
                    <div class="w-full h-full p-8px">
                        {{ data.component.comments || t('none') }}
                    </div>
                </ElTabPane>
            </ElTabs>
        </div>
    </div>
</template>


<style>
.el-form--label-left {
    .el-form-item {
        >label {
            justify-content: flex-start;
        }
    }
}

.el-tabs__content {
    height: 100%;
    overflow-x: hidden;
    overflow-y: auto;
    scrollbar-width: thin;
}

.properties-items {
    &:nth-child(2n) {
        background: #f3f3f388;
    }
}
</style>